#include "Tree.h"


Tree::Tree() : Mesh(), bFire(false), bLeaves(false), counter(0.0), bFog(false), render_mode(3), 
				fx_m_World(0), fx_m_WorldViewProj(0), fx_m_L_ViewProj(0), fx_tex_shadow_map(0), fx_lights(0), 
				fx_num_lights(0), fx_pEye(0), fx_bShadowed(0), fx_bUsePCSS(0), srv_heightmap(0), srv_sand(0)
{
	isShadowCaster(true);
	isShadowReceiver(true);	
}

Tree::~Tree() 
{
	try
	{
		if (srv_heightmap)
			srv_heightmap->Release();
		if (srv_sand)
			srv_sand->Release();
	}
	catch(...)
	{
		MessageBoxA(0, "exception thrown in  destructor", 0, 0);
	}
}

void Tree::draw(int subset, ID3DX11Effect* fx, const char* technique) const
{
	Mesh::draw(0, fx, technique);
}

void Tree::changeRenderMode()
{
	render_mode++;

	if (render_mode == NUM_RENDER_MODES)
		render_mode = 0;
}

XMFLOAT4X4 Tree::getSubsetMatrix(UINT subset) const
{
	return mtxWorld();
}


void Tree::init(const char* filename, ID3D11Device* g_device, ID3D11DeviceContext* g_context)
{
	
	Mesh::init(filename, g_device, g_context);
	
	_leaves.init("", g_device, g_context);

	//////////////////////////
	bFire = false;

	m_numSubsets = 1;

	//////////////////////////
	


	createEffect("../Desert_Island/shaders/tree.fxo", g_device);

	fx_m_World				= getFX()->GetVariableByName("m_World")->AsMatrix();
	fx_m_WorldViewProj		= getFX()->GetVariableByName("m_WorldViewProj")->AsMatrix();
	fx_m_L_ViewProj			= getFX()->GetVariableByName("m_L_ViewProj")->AsMatrix();
	
	fx_tex_shadow_map		= getFX()->GetVariableByName("tex_shadow_map")->AsShaderResource();

	fx_lights				= getFX()->GetVariableByName("lights");

	fx_num_lights			= getFX()->GetVariableByName("num_lights")->AsScalar();

	fx_pEye					= getFX()->GetVariableByName("pEye")->AsVector();
	fx_bShadowed			= getFX()->GetVariableByName("bShadowed")->AsScalar();
	fx_bUsePCSS				= getFX()->GetVariableByName("bUsePCSS")->AsScalar();

	///////////

	HRESULT hr = D3DX11CreateShaderResourceViewFromFile(g_dev(), L"../Desert_island/media/tree_heightmap.jpg", 0, 0, &srv_heightmap, 0);
	if (FAILED(hr))
		MessageBoxA(0, "Error creating tree heightmap srv", 0, 0);

	
	
	///////////

	// Input layout - Vertex IA
	D3D11_INPUT_ELEMENT_DESC vertex_layout[] = {
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "NORMAL", 0,  DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TANGENT", 0,  DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEX_COORDS", 0,  DXGI_FORMAT_R32G32_FLOAT, 0, 36, D3D11_INPUT_PER_VERTEX_DATA, 0 }
	};

	D3DX11_PASS_DESC passDesc;
	ID3DX11EffectTechnique* tech = getFX()->GetTechniqueByIndex(0);
	tech->GetPassByIndex(0)->GetDesc(&passDesc);

	hr = createInputLayout(g_dev(), vertex_layout, 4, passDesc.pIAInputSignature, passDesc.IAInputSignatureSize);
	if (FAILED(hr))
		MessageBoxA(0, "Error creating tree IA", 0, 0);

}

void Tree::Update(float dt)
{

	if (bLeaves)
		_leaves.Update( dt);

	if (bFog)
		counter += dt;
}

void Tree::draw(const Camera& camera, const vector<Light*>& lights)
{

	ID3DX11EffectScalarVariable* fx_time = getFX()->GetVariableByName("border")->AsScalar();
	fx_time->SetFloat(counter);
	
	
	if (bLeaves)
		_leaves.draw(camera, lights);

	// Material
	Mesh::setMaterial(getFX());

	context()->IASetInputLayout(getInputLayout());


	// World Matrix
	XMMATRIX mWorld = XMLoadFloat4x4(&(mtxWorld()));
	fx_m_World->SetMatrix((float*)&mWorld);
	fx_m_WorldViewProj->SetMatrix((float*)&(mWorld * camera.getViewMatrix() * camera.getProjectionMatrix()));
	fx_pEye->SetFloatVector((float*)&(camera.getPosVector3()));

	// Light // mView, shadow_map, light params
	for (unsigned int i=0; i<lights.size(); ++i)
	{
		fx_m_L_ViewProj =	getFX()->GetVariableByName("m_L_ViewProj")->GetElement(i)->AsMatrix();
		fx_lights =			getFX()->GetVariableByName("lights")->GetElement(i);
		fx_tex_shadow_map = getFX()->GetVariableByName("tex_shadow_map")->GetElement(i)->AsShaderResource();
		
		fx_m_L_ViewProj->SetMatrix(		(float*)&(lights[i]->getViewProjMatrix())	);
		fx_tex_shadow_map->SetResource(	lights[i]->getShadowMapSRV())	;
		fx_lights->SetRawValue(	(void*)&(lights[i]->getLightStructure()), 0, sizeof(Light_Params)	);
	}
	ID3DX11EffectScalarVariable*	fx_shadow_size = getFX()->GetVariableByName("shadow_size")->AsScalar();
	fx_shadow_size->SetInt(lights[0]->getShadowMapSize());
	fx_num_lights->SetInt(lights.size());
	

	fx_bShadowed->SetBool(isShadowReceiver());
	fx_bUsePCSS->SetBool(PCSS());

	ID3DX11EffectScalarVariable*  fx_bLit = getFX()->GetVariableByName("bLit")->AsScalar();
	fx_bLit->SetBool(isLit());

	if (render_mode == Tree::NonTexturedNonLitWireframe)
		Mesh::draw(0, getFX(), "Tree_NonTexturedNonLitWireframe"); 
	else if (render_mode == Tree::NonTexturedFlatShaded)
		Mesh::draw(0, getFX(), "Tree_NonTexturedFlatShaded"); 
	else if (render_mode == Tree::NonTexturedSmoothShaded)
		Mesh::draw(0, getFX(), "Tree_NonTexturedSmoothShaded");
	else if (render_mode == Tree::TexturedSmoothShaded)
		Mesh::draw(0, getFX(), "Tree");
	else
	{
		ID3DX11EffectShaderResourceVariable*	fx_tex_heightmap = getFX()->GetVariableByName("tex_heightmap")->AsShaderResource();
		fx_tex_heightmap->SetResource(srv_heightmap);

		Mesh::draw(0, getFX(), "Tree_DisplacementMapping");
	}

	for (unsigned int i=0; i<lights.size(); ++i) {
		fx_tex_shadow_map = getFX()->GetVariableByName("tex_shadow_map")->GetElement(i)->AsShaderResource();
		fx_tex_shadow_map->SetResource(0);
	}
	ID3DX11EffectTechnique* tech = getFX()->GetTechniqueByName("Tree");
	tech->GetPassByIndex(0)->Apply(0, context());

}

void Tree::catchFire()
{
}

void Tree::sproutLeaves()
{
	bLeaves = true;
	_leaves.setActive(true);

}

void Tree::endFire()
{
}
		
void Tree::dropLeaves()
{
	_leaves.drop();
}

void Tree::startFog()
{
	if (bFog) return;
	
	bFog = true;
	counter = 0.0f;
}

void Tree::reset()
{
	bFog = false;
}

void Tree::drawFire(CXMMATRIX mVP, const XMFLOAT4& pos, float dt)
{
}

void Tree::generateEmitters(UINT subset, UINT global_ID, ID3DX11Effect* fxDefault, const char* techDefault)
{
	draw(0, fxDefault, techDefault);
}